//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_comment_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/comment_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/dao/watch_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_comment"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_comment_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectCommentApiImpl) AddComment(ctx context.Context, req *project_comment_api.AddCommentRequest) (*project_comment_api.AddCommentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.AddCommentResponse{
			Code:   project_comment_api.AddCommentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.AddCommentResponse{
			Code:   project_comment_api.AddCommentResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.AddCommentResponse{
			Code:   project_comment_api.AddCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_comment_api.AddCommentResponse{
			Code:   project_comment_api.AddCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查目标是否存在
	exist, err := apiImpl.checkTarget(ctx, req.ProjectId, req.TargetType, req.TargetId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_comment_api.AddCommentResponse{
			Code:   project_comment_api.AddCommentResponse_CODE_NO_TARGET,
			ErrMsg: "评论目标不存在",
		}, nil
	}
	//获取关注人员
	watchTargetType := apiImpl.convertWatchTargetType(req.TargetType)
	watchUserIdList, err := watch_dao.MyWatchDao.DistinctUserId(ctx, req.ProjectId, uint32(watchTargetType), req.TargetId)
	if err != nil {
		return nil, err
	}

	commentId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		//写入评论
		err = comment_dao.CommentDao.Insert(sessCtx, &comment_dao.CommentDbItem{
			CommentId:  commentId,
			ProjectId:  req.ProjectId,
			TargetId:   req.TargetId,
			TargetType: uint32(req.TargetType),
			SendUserId: sessionItem.UserId,
			SendTime:   nowTime,
			Content:    req.Content,
		})
		if err != nil {
			return nil, err
		}
		//更新关注用户未读信息
		for _, watchUserId := range watchUserIdList {
			if watchUserId == sessionItem.UserId { //不通知自己
				continue
			}
			err = comment_dao.UnReadDao.Remove(sessCtx, req.ProjectId, watchUserId, uint32(req.TargetType), req.TargetId)
			if err != nil {
				return nil, err
			}
			err = comment_dao.UnReadDao.Insert(sessCtx, &comment_dao.UnReadInfoDbItem{
				ProjectId:  req.ProjectId,
				UserId:     watchUserId,
				TargetType: uint32(req.TargetType),
				TargetId:   req.TargetId,
				TimeStamp:  nowTime,
			})
			if err != nil {
				return nil, err
			}
		}
		return &project_comment_api.AddCommentResponse{
			Code:      project_comment_api.AddCommentResponse_CODE_OK,
			CommentId: commentId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送新评论通知
	for _, watchUserId := range watchUserIdList {
		if watchUserId == sessionItem.UserId { //不通知自己
			continue
		}
		go api_common.SendNoticeToUser(context.Background(), watchUserId, &notices_comment.AddCommentNotice{
			ProjectId:  req.ProjectId,
			CommentId:  commentId,
			TargetType: uint32(req.TargetType),
			TargetId:   req.TargetId,
		})
	}
	return ret.(*project_comment_api.AddCommentResponse), nil
}

func (apiImpl *ProjectCommentApiImpl) ListComment(ctx context.Context, req *project_comment_api.ListCommentRequest) (*project_comment_api.ListCommentResponse, error) {
	emptyList := []*project_comment_api.Comment{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.ListCommentResponse{
			Code:        project_comment_api.ListCommentResponse_CODE_WRONG_SESSION,
			ErrMsg:      "会话不存在",
			CommentList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.ListCommentResponse{
			Code:        project_comment_api.ListCommentResponse_CODE_NO_PROJECT,
			ErrMsg:      "项目不存在",
			CommentList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.ListCommentResponse{
			Code:        project_comment_api.ListCommentResponse_CODE_NO_PERMISSION,
			ErrMsg:      "没有权限",
			CommentList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	count, err := comment_dao.CommentDao.Count(ctx, req.ProjectId, uint32(req.TargetType), req.TargetId)
	if err != nil {
		return nil, err
	}
	commentItemList, err := comment_dao.CommentDao.List(ctx, req.ProjectId, uint32(req.TargetType), req.TargetId, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}

	//获取用户信息
	userIdList := []string{}
	for _, commentItem := range commentItemList {
		userIdList = append(userIdList, commentItem.SendUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//生成结果
	commentList := []*project_comment_api.Comment{}
	for _, commentItem := range commentItemList {
		comment := commentItem.ToComment()
		userItem, ok := userItemMap[commentItem.SendUserId]
		if ok {
			comment.SendDisplayName = userItem.BasicInfo.DisplayName
			comment.SendLogoUri = userItem.BasicInfo.LogoUri
		}
		commentList = append(commentList, comment)
	}

	return &project_comment_api.ListCommentResponse{
		Code:        project_comment_api.ListCommentResponse_CODE_OK,
		TotalCount:  count,
		CommentList: commentList,
	}, nil
}

func (apiImpl *ProjectCommentApiImpl) GetComment(ctx context.Context, req *project_comment_api.GetCommentRequest) (*project_comment_api.GetCommentResponse, error) {
	emptyComment := &project_comment_api.Comment{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.GetCommentResponse{
			Code:    project_comment_api.GetCommentResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			Comment: emptyComment,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.GetCommentResponse{
			Code:    project_comment_api.GetCommentResponse_CODE_NO_PROJECT,
			ErrMsg:  "项目不存在",
			Comment: emptyComment,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.GetCommentResponse{
			Code:    project_comment_api.GetCommentResponse_CODE_NO_PERMISSION,
			ErrMsg:  "没有权限",
			Comment: emptyComment,
		}, nil
	} else if err != nil {
		return nil, err
	}

	commentItem, err := comment_dao.CommentDao.Get(ctx, req.CommentId, req.ProjectId, uint32(req.TargetType), req.TargetId)
	if err != nil {
		return &project_comment_api.GetCommentResponse{
			Code:    project_comment_api.GetCommentResponse_CODE_NO_COMMENT,
			ErrMsg:  "评论不存在",
			Comment: emptyComment,
		}, nil
	}
	//获取用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, []string{commentItem.SendUserId})
	if err != nil {
		return nil, err
	}
	//生成结果
	comment := commentItem.ToComment()
	if len(userItemList) > 0 {
		comment.SendDisplayName = userItemList[0].BasicInfo.DisplayName
		comment.SendLogoUri = userItemList[0].BasicInfo.LogoUri
	}

	return &project_comment_api.GetCommentResponse{
		Code:    project_comment_api.GetCommentResponse_CODE_OK,
		Comment: comment,
	}, nil
}

func (apiImpl *ProjectCommentApiImpl) UpdateComment(ctx context.Context, req *project_comment_api.UpdateCommentRequest) (*project_comment_api.UpdateCommentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.UpdateCommentResponse{
			Code:   project_comment_api.UpdateCommentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.UpdateCommentResponse{
			Code:   project_comment_api.UpdateCommentResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.UpdateCommentResponse{
			Code:   project_comment_api.UpdateCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_comment_api.UpdateCommentResponse{
			Code:   project_comment_api.UpdateCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	commentItem, err := comment_dao.CommentDao.Get(ctx, req.CommentId, req.ProjectId, uint32(req.TargetType), req.TargetId)
	if err != nil {
		return &project_comment_api.UpdateCommentResponse{
			Code:   project_comment_api.UpdateCommentResponse_CODE_NO_COMMENT,
			ErrMsg: "评论不存在",
		}, nil
	}
	if commentItem.SendUserId != sessionItem.UserId {
		return &project_comment_api.UpdateCommentResponse{
			Code:   project_comment_api.UpdateCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "只能修改自己的评论",
		}, nil
	}
	nowTime := time.Now().UnixNano() / 1e6
	if nowTime-(3600*1000) > commentItem.SendTime {
		return &project_comment_api.UpdateCommentResponse{
			Code:   project_comment_api.UpdateCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "只能修改一小时内的评论",
		}, nil
	}
	exist, err := apiImpl.checkTarget(ctx, req.ProjectId, req.TargetType, req.TargetId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_comment_api.UpdateCommentResponse{
			Code:   project_comment_api.UpdateCommentResponse_CODE_NO_TARGET,
			ErrMsg: "评论目标不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = comment_dao.CommentDao.UpdateContent(sessCtx, req.CommentId, req.ProjectId, uint32(req.TargetType), req.TargetId, req.Content)
		if err != nil {
			return nil, err
		}
		return &project_comment_api.UpdateCommentResponse{
			Code: project_comment_api.UpdateCommentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送更新通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_comment.UpdateCommentNotice{
		ProjectId:  req.ProjectId,
		CommentId:  req.CommentId,
		TargetType: uint32(req.TargetType),
		TargetId:   req.TargetId,
	})
	return ret.(*project_comment_api.UpdateCommentResponse), nil
}

func (apiImpl *ProjectCommentApiImpl) RemoveComment(ctx context.Context, req *project_comment_api.RemoveCommentRequest) (*project_comment_api.RemoveCommentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.RemoveCommentResponse{
			Code:   project_comment_api.RemoveCommentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.RemoveCommentResponse{
			Code:   project_comment_api.RemoveCommentResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.RemoveCommentResponse{
			Code:   project_comment_api.RemoveCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_comment_api.RemoveCommentResponse{
			Code:   project_comment_api.RemoveCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	commentItem, err := comment_dao.CommentDao.Get(ctx, req.CommentId, req.ProjectId, uint32(req.TargetType), req.TargetId)
	if err != nil {
		return &project_comment_api.RemoveCommentResponse{
			Code:   project_comment_api.RemoveCommentResponse_CODE_NO_COMMENT,
			ErrMsg: "评论不存在",
		}, nil
	}
	if !(commentItem.SendUserId == sessionItem.UserId || projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_comment_api.RemoveCommentResponse{
			Code:   project_comment_api.RemoveCommentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有删除权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = comment_dao.CommentDao.Remove(sessCtx, req.CommentId, req.ProjectId, uint32(req.TargetType), req.TargetId)
		if err != nil {
			return nil, err
		}
		return &project_comment_api.RemoveCommentResponse{
			Code: project_comment_api.RemoveCommentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送删除通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_comment.RemoveCommentNotice{
		ProjectId:  req.ProjectId,
		CommentId:  req.CommentId,
		TargetType: uint32(req.TargetType),
		TargetId:   req.TargetId,
	})
	return ret.(*project_comment_api.RemoveCommentResponse), nil
}
